<template>
	<view class="recorder" @click="showPicker">
		<slot></slot>
		<view class="mask" @click.stop="cancel" v-if="isShow"></view>

		<view class="conbox record" :class="{ pickerShow: isShow }" @click.stop="handle">
			<view class="re-top" v-if="showTop">
				<view class="re-cancel" @click="cancel">取消</view>
				<view class="re-confirm" @click="confirm">确定</view>
			</view>

			<view class="recorder-box" v-if="!finish" @longpress="onStartRecoder" @touchcancel="onEndRecoder" @touchend="onEndRecoder">
				<u-circle-progress :duration="0" :percent="calcProgress || 100" v-if="isShow">
					<view class="progress-content"><image class="img" src="/static/voice.png" mode="aspectFit"></image></view>
				</u-circle-progress>
			</view>
			<view class="recorder-box" v-else @click.stop="playVoice">
				<u-circle-progress :duration="0" :percent="playProgress || 100" v-if="isShow">
					<view class="progress-content">
						<image class="img" src="/static/play.png" mode="aspectFit" v-if="!playStatus"></image>
						<image class="img" src="/static/pause.png" mode="aspectFit" v-else></image>
					</view>
				</u-circle-progress>
			</view>

			<view class="now-date">{{ reDate }}</view>
			<view class="title" v-if="!finish">长按录制语音</view>
			<view class="title" @click="reset" v-else>重新录制</view>
		</view>
	</view>
</template>

<script>
let recorderManager = uni.getRecorderManager();
let innerAudioContext = uni.createInnerAudioContext();
export default {
	props: {
		showTop: {
			type: Boolean,
			default: true
		},
		maximum: {
			type: Number,
			default: 60
		},
		duration: {
			type: Number,
			default: 20
		}
	},
	data() {
		return {
			isShow: false,
			reDate: '00:00',
			sec: 0,
			min: 0,
			finish: false,
			voicePath: '',
			playProgress: 100,
			playTimer: null,
			timer: null,
			playStatus: false
		};
	},
	created() {
		this.onMonitorEvents();
		
		try {
			uni.authorize({
				scope: 'scope.record',
				success: (res) => {
					console.log('录音授权成功', res);
				}
			});
		} catch (e) {
			//TODO handle the exception
		}
	},
	computed: {
		calcProgress() {
			return ((this.sec + this.min * 60) / this.maximum) * 100;
		}
	},
	methods: {
		showPicker() {
			this.isShow = true;
			this.$emit('show');
		},
		confirm() {
			if (innerAudioContext) {
				innerAudioContext.destroy();
			}
			innerAudioContext = '';
			this.isShow = false;
			this.playStatus = false;
			this.$emit('confirm', this.voicePath);

			this.reset();
		},
		cancel() {
			if (innerAudioContext) {
				innerAudioContext.destroy();
			}
			innerAudioContext = '';
			this.isShow = false;
			this.playStatus = false;
			this.$emit('cancel');

			this.reset();
		},
		handle() {
			this.$emit('click');
		},
		reset() {
			this.voicePath = '';
			this.min = 0;
			this.sec = 0;
			this.reDate = '00:00';
			this.playProgress = 100;
			this.playStatus = false;
			this.finish = false;
			this.$emit('reset');
		},
		playVoice() {
			if (!innerAudioContext) {
				innerAudioContext = uni.createInnerAudioContext();
			}
			innerAudioContext.src = this.voicePath;

			if (!this.playStatus) {
				innerAudioContext.play();
			} else {
				innerAudioContext.pause();
			}
			this.$emit('playVoice', this.playStatus);
		},
		onEndRecoder() {
			recorderManager.stop();
		},
		onStartRecoder() {
			// 语音识别格式支持：pcm, wav, amr, m4a
			// 语音播放格式支持：m4a, wav, mp3, aac
			// format有效值 aac, mp3, wav, pcm
			recorderManager.start({
				sampleRate: 16000,
				numberOfChannels: 1,
				format: 'mp3',
				duration: this.maximum * 1000
			});
		},
		onMonitorEvents() {
			recorderManager.onStart(() => {
				uni.showLoading({
					title: '录制中...'
				});
				this.startDate();
				this.$emit('start');
			});
			recorderManager.onStop(({ tempFilePath }) => {
				this.voicePath = tempFilePath;
				clearInterval(this.timer);
				uni.hideLoading();
				this.finish = true;
				this.$emit('end');
			});
			innerAudioContext.onTimeUpdate(() => {
				let totalDate = innerAudioContext.duration;
				let nowTime = innerAudioContext.currentTime;
				let surplus = totalDate - nowTime;
				this.playProgress = (surplus / totalDate) * 100;

				let _min = Math.floor(surplus / 60);
				if (_min < 10) _min = '0' + _min;
				let _sec = Math.floor(surplus % 60);
				if (_sec < 10) _sec = '0' + _sec;
				this.reDate = _min + ':' + _sec;
			});
			innerAudioContext.onPlay(() => {
				this.playStatus = true;
				this.$emit('play');
			});
			innerAudioContext.onPause(() => {
				clearInterval(this.timer);
				this.playStatus = false;
				this.$emit('stop');
			});
			innerAudioContext.onEnded(() => {
				this.resetDate();
				this.playProgress = 100;
				this.playStatus = false;
				this.$emit('stop');
			});
		},
		startDate() {
			clearInterval(this.timer);
			this.sec = 0;
			this.min = 0;
			this.timer = setInterval(() => {
				this.sec += this.duration / 1000;
				if (this.sec >= 60) {
					this.min++;
					this.sec = 0;
				}
				this.resetDate();
			}, this.duration);
		},
		resetDate() {
			let _s = this.sec < 10 ? '0' + parseInt(this.sec) : parseInt(this.sec);
			let _m = this.min < 10 ? '0' + this.min : this.min;
			this.reDate = _m + ':' + _s;
		}
	}
};
</script>

<style lang="scss">
.recorder {
	.mask {
		position: fixed;
		z-index: 1000;
		top: 0;
		right: 0;
		left: 0;
		bottom: 0;
		background: rgba(0, 0, 0, 0.6);
	}

	.conbox {
		overflow: hidden;
		text-align: center;
		transition: all 0.3s ease;
		transform: translateY(100%);
		&.pickerShow {
			transform: translateY(0);
		}

		position: fixed;
		z-index: 1000;
		right: 0;
		left: 0;
		bottom: 0;
		background: #fff;
	}

	.progress-content {
		.img {
			width: 60rpx;
			height: 60rpx;
		}
	}

	.re-top {
		display: flex;
		justify-content: space-between;
		padding: 0 40rpx;
		font-size: 16px;
		line-height: 90rpx;

		.re-confirm {
			color: #e5231a;
		}
	}

	.title {
		font-size: 16px;
		padding-bottom: 20rpx;
	}

	.recorder-box {
		position: relative;
	}

	.now-date {
		font-size: 16px;
	}
}
</style>
